﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XSTDZ.ERP.Application.DataContracts;
using AutoMapper;
using XSTDZ.ERP.Domain.Models;
using XSTDZ.ERP.Core.Repositories;
using XSTDZ.ERP.Core.Generator;

namespace XSTDZ.ERP.Application.Implements
{
    public class ProductOutServiceImpl : ApplicationServiceBase, IProductOutService
    {
        IRepository<ProductSellBill> _outBillRepository;
        IRepository<ProductSellBillDetail> _outBillDetailRepository;
        IRepository<Stock> _stockRepository;
        IRepository<ReceivablePayableBill> _billReceRepository;
        public ProductOutServiceImpl(IRepositoryContext repositoryContext, IRepository<ProductSellBill> outBillRepository, IRepository<ProductSellBillDetail> outBillDetailRepository, IRepository<Stock> stockRepository, IRepository<ReceivablePayableBill> billReceRepository)
            : base(repositoryContext)
        {
            this._outBillRepository = outBillRepository;
            this._outBillDetailRepository = outBillDetailRepository;
            this._stockRepository = stockRepository;
            this._billReceRepository = billReceRepository;
        }

        public void ConvertProductOutBillDeleteState(Guid outBillId)
        {
            var itemIds = _outBillRepository.GetByKey(outBillId).ProductSellBillDetails.Select(p => p.Id).ToList().AsEnumerable();
            ConvertProductDelete(outBillId, itemIds, true);
        }

        public ProductOutBillDto GetProductOutBill(Guid outBillId)
        {
            var productBill = this._outBillRepository.GetByKey(outBillId);

            productBill.Auditor = productBill.Auditor ?? new User(); //发布版本要去掉
            productBill.Client = productBill.Client ?? new ClientInfo();//发布版本要去掉

            return Mapper.Map<ProductSellBill, ProductOutBillDto>(productBill);
        }

        public IEnumerable<ProductOutBillDto> GetProductOutBills(int pageIndex, int pageSize)
        {
            var orderby = new OrderByParameter<ProductSellBill>(m => m.CreateTime, SortOrder.Descending);

            var productOutBills = this._outBillRepository.GetAll(1, 100, new[] { orderby });
            productOutBills.Each(p => {
                p.Auditor = p.Auditor ?? new User(); //发布版本要去掉
                p.Client = p.Client ?? new ClientInfo();//发布版本要去掉
            });
            return Mapper.Map<IEnumerable<ProductSellBill>, IEnumerable<ProductOutBillDto>>(productOutBills);
        }

        public void ConvertProductOutBillDeleteState(Guid outBillId, IEnumerable<Guid> outBillDetailIds)
        {
            ConvertProductDelete(outBillId, outBillDetailIds, false);
        }

        private void ConvertProductDelete(Guid outBillId, IEnumerable<Guid> outBillDetailIds,bool isAll)
        {
            var productOutBill = this._outBillRepository.GetByKey(outBillId);
            var productBillItemIds = productOutBill.ProductSellBillDetails.Where(p => outBillDetailIds.ToArray().Contains(p.Id));
            if (isAll) {
                productOutBill.SetDeleteState();
            }
            productOutBill.SetChildrenDeleteState(productBillItemIds);
            this._outBillRepository.Update(productOutBill);
            this.Context.Commit();
        }

        public Guid AddOrUpdateProductOutBill(ProductOutBillDto outBillDto, IEnumerable<ProductOutBillDetailDto> outBillDetailDtos)
        {
            if (IsHasStockTooBigNum(outBillDetailDtos)) { return Guid.Empty; }//检测是否有超过库存数量的销售单据
            var isExistsBill = this._outBillRepository.Exists(b=>b.Id==outBillDto.ID);
            if (isExistsBill)
            {
               return UpdateProductOutBill(outBillDto, outBillDetailDtos);//更新
            }
            else
            {
               return AddProductOutBill(outBillDto, outBillDetailDtos);//添加
            }
        }
        public Guid AddProductOutBill(ProductOutBillDto outBillDto, IEnumerable<ProductOutBillDetailDto> outBillDetailDtos)
        {
           
            var productOutBill = Mapper.Map<ProductOutBillDto, ProductSellBill>(outBillDto);
            var productOutBillDetails = Mapper.Map<IEnumerable<ProductOutBillDetailDto>, IEnumerable<ProductSellBillDetail>>(outBillDetailDtos);
            productOutBill.Init().ClearChildrenAll().AddChildren(productOutBillDetails);

            //var stocks = GetStockDto(productOutBillDetails);//添加库存
            //UpdateStock(stocks);

            this._outBillRepository.Add(productOutBill);
            this.Context.Commit();
            return productOutBill.Id;
        }
        /// <summary>
        /// 检测是否有超过库存数量的销售单据
        /// </summary>
        /// <param name="ps"></param>
        /// <returns></returns>
        private bool IsHasStockTooBigNum(IEnumerable<ProductOutBillDetailDto> ps)
        {
            if ( ps != null && ps.Count() > 0)
            {
                foreach (var item in ps)
                {
                    if (item.SellAmount <= 0)//|| item.ReadyCount <= 0 备货数量不小于0
                    {
                        return true;
                        break;
                    }
                    if (_stockRepository.Exists(s => s.Id == item.StockID && s.StockCount < (item.SellAmount+item.ReadyCount)))
                    {
                        return true;
                        break;
                    }
                }
            }
            return false;
        }

        #region 反审核
        public int UnAudit(Guid outBillId)
        {
            var pinBills = this._outBillRepository.GetByKey(outBillId);
            if (pinBills.BillState == 1 && pinBills.AuditState == 1)//已提交，审核通过
            {
              var rb=  this._billReceRepository.Get(t => !t.BillClassify && t.BillType == 0 && t.BusinessID == outBillId);
              if (rb!=null)
              { 
                  if(((rb.BillReceiv??0m)+(rb.BillReceivPft??0m))>0m)//已开始收款(不能进行删除
                  {
                      return -1;//已开始收款
                  }
                  #region 更新数据
                  
                  //1:更新销售订单数据
                  pinBills.AuditState = 0;//未审核
                  pinBills.BillState = 0;//保存
                 //2:删除账单
                  this._billReceRepository.Remove(rb);
                  //3：回算库存
                  UpdateStock(pinBills.ProductSellBillDetails.ToList(), false);
                  this.Context.Commit();

                  #endregion
                  return 9;
              }
            }
            return 0;
        }
        #endregion
        #region 审核


        //审核
        public void Audit(Dictionary<Guid,int> outBillIds, Guid auditId, Guid orgId)
        {

            var pinBills = this._outBillRepository.GetByKey(outBillIds.Keys.FirstOrDefault());// this._outBillRepository.GetAll(t => outBillIds.Keys.ToArray().Contains(t.Id)&&t.BillState==1 &&t.AuditState!=1);
            if (pinBills.BillState == 1 && pinBills.AuditState == 0)//已提交，未审核
            {
                var recelst = new List<ReceivablePayableBill>();

                pinBills.AuditorID = auditId;
                pinBills.AuditState = outBillIds.Values.First();
                pinBills.AuditTime = DateTime.Now;
                if (pinBills.AuditState == 1)//审核通过
                {
                    recelst.Add(CreateReceivablePayableBill(pinBills, auditId, orgId));// 生成账单
                    if (recelst != null && recelst.Count > 0)
                    {
                        ReceivablePayableServiceImpl rb = new ReceivablePayableServiceImpl(this.Context, this._billReceRepository, null);
                        rb.CreateReceivablePayable(recelst);
                    }
                }
                else if(pinBills.AuditState == 2)//审核不通过(回滚库存)
                {
                    UpdateStock(pinBills.ProductSellBillDetails.ToList(),false);
                }
                if (pinBills != null )
                {
                    this._outBillRepository.Update(pinBills);
                    this.Context.Commit();
                }
            }
        }
        //提交(扣库存)
        public void Confirm(IList<Guid> outBillIds, Guid orgId)
        {
            var pinBills = this._outBillRepository.GetByKey(outBillIds.First());// this._outBillRepository.GetAll(t => outBillIds.Contains(t.Id) && t.BillState != 1);
            if (pinBills != null )
            {
                pinBills.UpdateDate = DateTime.Now;
                bool isNeedAudit = false;
                #region 判断是否自动审核(销售单价有小于规定价的)

                var tempStockIds=pinBills.ProductSellBillDetails.Select(t=>t.StockID);
                var prices = _stockRepository.GetAll(t => tempStockIds.Contains(t.Id)).Select(s => s.ProductInfo).Select(t => new { productId = t.Id, sellprice = t.SellPrice });

              foreach (var item in pinBills.ProductSellBillDetails)
              {
                  foreach (var p in prices)
                  {
                      if (p.productId == item.Stock.ProductID)
                      {
                          if (item.SellPrice < Convert.ToDecimal(p.sellprice))
                          {
                              isNeedAudit = true;
                              break;
                          }
                      }
                  }
              }
                #endregion
              //  pinBills.Each(t => { t.BillState = 1; UpdateStock(t.ProductSellBillDetails.ToList(), true); });//提交扣库存
              pinBills.BillState = 1;
              UpdateStock(pinBills.ProductSellBillDetails.ToList(), true);//提交扣库存
              if (!isNeedAudit)//销售单价都在规定范围内 自动审核
              {
                  pinBills.AuditorID = pinBills.UpdateID;
                  pinBills.AuditState = 1;
                  pinBills.AuditTime = pinBills.UpdateDate;
                  #region 自动审核 生成账单
                  var recelst = new List<ReceivablePayableBill>();
                  Guid audioUserId = pinBills.UpdateID ?? pinBills.CreateID;
                  recelst.Add(CreateReceivablePayableBill(pinBills, audioUserId, orgId));// 生成账单
                  if (recelst != null && recelst.Count > 0)
                  {
                      ReceivablePayableServiceImpl rb = new ReceivablePayableServiceImpl(this.Context, this._billReceRepository, null);
                      rb.CreateReceivablePayable(recelst);
                  }
                  #endregion
              }
            
                this._outBillRepository.Update(pinBills);
                this.Context.Commit();
            }
        }
        private ReceivablePayableBill CreateReceivablePayableBill(ProductSellBill sbill, Guid auditId,Guid orgId)
        {
            var bill = new ReceivablePayableBill();
            bill.ClientID = sbill.ClientID;
            bill.BillClassify = false;//收款
            bill.BillType = 0;//销售订单
            bill.BusinessID = sbill.Id;
            bill.CreateID = auditId;
            bill.OrgID = orgId;
            //总应收款
            bill.BillReceivable = sbill.ProductSellBillDetails.Where(t => t.Deleted == 0).Select(t => (decimal)((decimal)t.SellAmount * t.SellPrice)).Sum();
            return bill;
        }
        #endregion
        //更新库存，提交即扣库存，审核未通过就把扣的库存加回去
        private void UpdateStock(IList<ProductSellBillDetail>  outBillDetail,bool isSell)
        {
            #region 更新操作明细，更新库存
            var stockDtos = new List<Stock>();
            
            outBillDetail.Each(t =>
            {
                Stock stockDto  = new Stock();//库存数据
                stockDto.StockCount = isSell ? -t.SellAmount-(float)t.ReadyCount : t.SellAmount+(float)t.ReadyCount;//(-:需要向库存减数量 ,+把之前的数量加回去)
                stockDto.StorehouseID = t.StockID;
                stockDto.Id = t.StockID;
                stockDtos.Add(stockDto);
            });
            UpdateStock(stockDtos);//更新库存
            #endregion
        }
      
        public Guid UpdateProductOutBill(ProductOutBillDto outBillDto, IEnumerable<ProductOutBillDetailDto> outBillDetailDtos)
        {
            
            #region 更新操作明细，更新库存
            var pinBill = this._outBillRepository.GetByKey(outBillDto.ID);
           
            outBillDto.CreateTime = pinBill.CreateTime;
            pinBill.UpdateDate = DateTime.Now;
            pinBill = Mapper.Map(outBillDto, pinBill);
            /*
            IList<Stock> stockDtos = new List<Stock>();//库存数据

            var productlDetails = Mapper.Map<IEnumerable<ProductOutBillDetailDto>, IEnumerable<ProductSellBillDetail>>(outBillDetailDtos);

            foreach (var p in pinBill.ProductSellBillDetails)
            {
                foreach (var pdto in outBillDetailDtos)
                {
                    if (p.Id == pdto.ID)
                    {

                        #region 先满足库存
                        var stock = new Stock
                        {
                            Id = pdto.StockID
                        };

                        if (p.StockID != pdto.StockID) ////更新明细时，修改了商品（品种），这里不可能出现没有库存的品种更改（介面控制）
                        {
                            stock.StockCount = -pdto.SellAmount;// 新品种需要减少数量
                            stockDtos.Add(stock);//进行添加


                            stockDtos.Add(new Stock
                            {
                                Id=p.StockID,
                                StockCount = p.SellAmount //把之前的数量加回去
                            });
                        }
                        else
                        {
                            stock.StockCount = -pdto.SellAmount;//需要向库存减数量
                            stockDtos.Add(stock);
                        }
                        #endregion

                        p.SellAmount = pdto.SellAmount;
                        p.StockID = pdto.StockID;
                        p.Remarks = pdto.Remarks;
                        p.SellPrice = pdto.SellPrice;
                      
                        break;
                    }
                }
            }
            //这部分是新增的明细行，需要进行写入数据库
            var insertItems=new List<ProductSellBillDetail>();
            if (pinBill.ProductSellBillDetails != null && pinBill.ProductSellBillDetails.Count() != 0)
            {
                productlDetails.Each(p =>
                {
                    var tag = false;
                    pinBill.ProductSellBillDetails.Each(i =>
                    {
                        if (p.Id == i.Id)
                        {
                            tag = true;
                        }
                    });
                    if (!tag)
                    {
                        insertItems.Add(p);
                    }

                });
            }
            else
            {
                insertItems = productlDetails.ToList();
            }
           
            if (insertItems.Count() != 0)
            {
                insertItems.Each(t => t.ProductSellBillID = pinBill.Id);
                this._outBillDetailRepository.Add(insertItems);
            }
            */
            this._outBillRepository.Update(pinBill);

          //  UpdateStock(stockDtos);//更新库存
            this.Context.Commit();
            return pinBill.Id;
            #endregion
        }
       
        public IEnumerable<ProductOutBillDetailDto> GetProductOutBillDetails(Guid outBillDetailId)
        {
            var productOutBillDetails = this._outBillDetailRepository.GetAll(p => p.ProductSellBillID == outBillDetailId);
            return Mapper.Map<IEnumerable<ProductSellBillDetail>, IEnumerable<ProductOutBillDetailDto>>(productOutBillDetails);
        }
        public Dictionary<ProductOutBillDto, IEnumerable<ProductOutBillDetailDto>> GetBillAndDetails(Guid outBillId)
        {
            var productOutBill = this._outBillRepository.GetByKey(outBillId);

            productOutBill.Auditor = productOutBill.Auditor ?? new User(); //发布版本要去掉
            productOutBill.Client = productOutBill.Client ?? new ClientInfo();//发布版本要去掉

            var billDto= Mapper.Map<ProductSellBill, ProductOutBillDto>(productOutBill);
            var billDetailDto = Mapper.Map<IEnumerable<ProductSellBillDetail>, IEnumerable<ProductOutBillDetailDto>>(productOutBill.ProductSellBillDetails.AsEnumerable());
            var result= new Dictionary<ProductOutBillDto, IEnumerable<ProductOutBillDetailDto>>();
            result.Add(billDto, billDetailDto);
            return result;
        }
        public IEnumerable<ProductOutBillDetailDto> GetProductOutBillDetails(int pageIndex, int pageSize)
        {
            throw new NotImplementedException();
        }

        #region 更新库存

        //private void AddOrUpdateStock(IEnumerable<ProductOutBillDetailDto> detailitems)
        //{
        //    StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
        //    stockServiceImpl.UpdateStockWithNoAdd(stockDtos);//更新库存
        //}
        private void UpdateStock(IList<Stock> stockDtos)
        {
            StockServiceImpl stockServiceImpl = new StockServiceImpl(this.Context, this._stockRepository);
            stockServiceImpl.UpdateStockWithNoAdd(stockDtos);//更新库存
        }
        /// <summary>
        /// 获得新增的库存
        /// </summary>
        /// <returns></returns>
        private IList<Stock> GetStockDto(IEnumerable<ProductOutBillDetailDto> detailitems)
        {
            var stocks = new List<Stock>();
            if (detailitems != null && detailitems.Count() != 0)
            {
                detailitems.Each(p =>
                {
                    stocks.Add(new Stock
                    {
                        Id = p.StockID,
                        StockCount =-p.SellAmount
                    });
                });
            }
            return stocks;
        }
        private IList<Stock> GetStockDto(IEnumerable<ProductSellBillDetail> detailitems)
        {
            var stocks = new List<Stock>();
            if (detailitems != null && detailitems.Count() != 0)
            {
                detailitems.Each(p =>
                {
                    stocks.Add(new Stock
                    {
                        Id = p.StockID,
                         StockCount=-p.SellAmount
                    });
                });
            }

            return stocks;
        }
       
        #endregion


        public string GetMaxBillNo()
        {
            var orderby = new OrderByParameter<ProductSellBill>(m => m.CreateTime, SortOrder.Descending);
            var billNo = this._outBillRepository.GetAll(1, 1, new[] { orderby }).FirstOrDefault();
            return billNo == null ? string.Empty : billNo.ProductSellBillNo;
        }
     
    }
}
